package com.spring.dynamic.job.config;

import com.spring.dynamic.job.config.task.Task;
import com.spring.dynamic.job.config.task.TaskRunService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * @author liuzhiqiang
 */
@Component
@Slf4j
public class TaskService {

    public static Map<String, Task> TASK_MAP = new HashMap<>();

    public static Map<String, TaskRunService> runServiceMap = new ConcurrentHashMap<>();

    @Autowired
    private TaskScheduler taskScheduler;

    /**
     * 取消任务
     *
     * @param taskName
     * @return
     */
    public Boolean cancelTask(String taskName) {
        Task task = getTask(taskName);
        if (task != null) {
            task.getScheduledFuture().cancel(true);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 开启任务
     *
     * @param taskName
     * @return
     */
    public Boolean startTask(String taskName) {
        Task task = getTask(taskName);
        if (task != null) {
            task.getScheduledFuture().cancel(false);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取任务状态
     *
     * @param taskName
     * @return
     */
    public Boolean getTaskState(String taskName) {
        Task task = getTask(taskName);
        if (task != null) {
            return task.getScheduledFuture().isDone();
        } else {
            throw new RuntimeException("任务不存在");
        }
    }


    /**
     * 修改任务 cron 不会立即生效
     *
     * @param taskName
     * @param cron
     * @return
     */
    public Boolean updateCronAfter(String taskName, String cron) {
        Task task = getTask(taskName);
        if (task != null) {
            task.setCorn(cron);
            return true;
        } else {
            return false;
        }
    }


    /**
     * 立即运行一次任务
     *
     * @param taskName
     * @return
     */
    public Boolean runTask(String taskName) {
        Task task = getTask(taskName);
        if (task != null) {
            TaskRunService taskRunService = TaskService.runServiceMap.get(task.getTaskName());
            if (taskRunService != null) {
                taskRunService.run(task);
            } else {
                log.info("无本地任务");
            }
            return true;
        } else {
            return false;
        }
    }


    public Task getTask(String taskName) {
        return TASK_MAP.get(taskName);
    }

    @PostConstruct
    public void init() {
        Task taskTest = new Task();
        taskTest.setTaskName("test");
        taskTest.setTaskDescribe("任务描述");
        taskTest.setCorn("0/20 * * * * ?");
        taskTest.setNextExecutionTime(new Date());
        Map<String, Object> parameter = new HashMap<>();
        parameter.put("key1", "value1");
        taskTest.setParameter(parameter);

        List<Task> list = new ArrayList<>();
        list.add(taskTest);

        for (Task task : list) {
            ScheduledFuture scheduledFuture = taskScheduler.schedule(() -> {
                runTask(task.getTaskName());
            }, triggerContext -> {
                if (StringUtils.isNotEmpty(task.getCorn())) {
                    CronTrigger cronTrigger = new CronTrigger(task.getCorn());
                    Date nextExecutionTime = cronTrigger.nextExecutionTime(triggerContext);
                    log.info("下次执行时间:{}", DateFormatUtils.format(nextExecutionTime, "yyyy-MM-dd HH:mm:ss"));
                    return nextExecutionTime;
                } else {
                    log.info("下次执行时间:取消");
                    return null;
                }
            });
            task.setScheduledFuture(scheduledFuture);
            TASK_MAP.put(task.getTaskName(), task);
        }
    }

}
